const express = require('express');
const { Op } = require('sequelize');
const { sequelize } = require('../config/database');
const User = require('../models/User');
const Activity = require('../models/Activity');
const auth = require('../middleware/auth');
const { body, query, validationResult } = require('express-validator');

const router = express.Router();

// @route   GET /api/users
// @desc    Get all users with pagination
// @access  Private
router.get('/', auth, async (req, res, next) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 20;
    const offset = (page - 1) * limit;

    const users = await User.findAll({
      where: { status: 'active' },
      attributes: { exclude: ['sessionKey', 'jwtToken'] },
      limit,
      offset,
      order: [['createdAt', 'DESC']]
    });

    const total = await User.count({ where: { status: 'active' } });

    res.json({
      success: true,
      data: {
        users,
        pagination: {
          page,
          limit,
          total,
          pages: Math.ceil(total / limit)
        }
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/:id
// @desc    Get user by ID
// @access  Public
router.get('/:id', async (req, res, next) => {
  try {
    const user = await User.findByPk(req.params.id, {
      include: [
        {
          association: 'followers',
          attributes: ['nickname', 'avatarUrl']
        },
        {
          association: 'following',
          attributes: ['nickname', 'avatarUrl']
        },
        {
          association: 'friends',
          attributes: ['nickname', 'avatarUrl']
        }
      ]
    });

    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Get user's recent activities
    const recentActivities = await Activity.findAll({ 
      where: { 
        creatorId: user.id, 
        status: { [Op.in]: ['published', 'ongoing', 'completed'] } 
      },
      attributes: ['title', 'type', 'startTime', 'endTime', 'location', 'mainImage', 'status'],
      order: [['createdAt', 'DESC']],
      limit: 6
    });

    // Get user's activity statistics
    const activityStats = await Activity.findAll({
      where: { creatorId: user.id },
      attributes: [
        'status',
        [sequelize.fn('COUNT', sequelize.col('id')), 'count']
      ],
      group: ['status']
    });

    res.json({
      success: true,
      data: {
        user: user.getPublicProfile(),
        recentActivities,
        activityStats
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   POST /api/users/:id/follow
// @desc    Follow a user
// @access  Private
router.post('/:id/follow', auth, async (req, res, next) => {
  try {
    const targetUserId = req.params.id;
    const currentUserId = req.user.userId;

    // Prevent self-follow
    if (targetUserId === currentUserId) {
      return res.status(400).json({
        success: false,
        message: 'You cannot follow yourself'
      });
    }

    const targetUser = await User.findByPk(targetUserId);
    const currentUser = await User.findByPk(currentUserId);

    if (!targetUser || !currentUser) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Check if already following
    const isFollowing = await currentUser.hasFollowing(targetUser);
    if (isFollowing) {
      return res.status(400).json({
        success: false,
        message: 'You are already following this user'
      });
    }

    // Add to following list
    await currentUser.addFollowing(targetUser);

    // Check if mutual follow to become friends
    const isMutualFollow = await targetUser.hasFollowing(currentUser);
    if (isMutualFollow) {
      await currentUser.addFriend(targetUser);
    }

    res.json({
      success: true,
      message: 'Successfully followed user'
    });

  } catch (error) {
    next(error);
  }
});

// @route   DELETE /api/users/:id/follow
// @desc    Unfollow a user
// @access  Private
router.delete('/:id/follow', auth, async (req, res, next) => {
  try {
    const targetUserId = req.params.id;
    const currentUserId = req.user.userId;

    const targetUser = await User.findByPk(targetUserId);
    const currentUser = await User.findByPk(currentUserId);

    if (!targetUser || !currentUser) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Remove from following list
    await currentUser.removeFollowing(targetUser);

    // Remove from friends list if they were friends
    const isFriend = await currentUser.hasFriend(targetUser);
    if (isFriend) {
      await currentUser.removeFriend(targetUser);
    }

    res.json({
      success: true,
      message: 'Successfully unfollowed user'
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/:id/followers
// @desc    Get user's followers
// @access  Public
router.get('/:id/followers', async (req, res, next) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 20;
    const offset = (page - 1) * limit;

    const user = await User.findByPk(req.params.id, {
      include: [{
        association: 'followers',
        attributes: ['nickname', 'avatarUrl', 'bio', 'statistics', 'createdAt'],
        through: { attributes: [] },
        limit,
        offset,
        order: [['createdAt', 'DESC']]
      }]
    });

    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    const total = await user.countFollowers();

    res.json({
      success: true,
      data: {
        followers: user.followers,
        pagination: {
          page,
          limit,
          total,
          pages: Math.ceil(total / limit)
        }
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/:id/following
// @desc    Get user's following
// @access  Public
router.get('/:id/following', async (req, res, next) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 20;
    const offset = (page - 1) * limit;

    const user = await User.findByPk(req.params.id, {
      include: [{
        association: 'following',
        attributes: ['nickname', 'avatarUrl', 'bio', 'statistics', 'createdAt'],
        through: { attributes: [] },
        limit,
        offset,
        order: [['createdAt', 'DESC']]
      }]
    });

    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    const total = await user.countFollowing();

    res.json({
      success: true,
      data: {
        following: user.following,
        pagination: {
          page,
          limit,
          total,
          pages: Math.ceil(total / limit)
        }
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/:id/friends
// @desc    Get user's friends
// @access  Public
router.get('/:id/friends', async (req, res, next) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 20;
    const offset = (page - 1) * limit;

    const user = await User.findByPk(req.params.id, {
      include: [{
        association: 'friends',
        attributes: ['nickname', 'avatarUrl', 'bio', 'statistics', 'createdAt'],
        through: { attributes: [] },
        limit,
        offset,
        order: [['createdAt', 'DESC']]
      }]
    });

    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    const total = await user.countFriends();

    res.json({
      success: true,
      data: {
        friends: user.friends,
        pagination: {
          page,
          limit,
          total,
          pages: Math.ceil(total / limit)
        }
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/search
// @desc    Search users by nickname or bio
// @access  Private
router.get('/search', auth, async (req, res, next) => {
  try {
    const q = req.query.q || '';
    const pageNum = parseInt(req.query.page) || 1;
    const limitNum = parseInt(req.query.limit) || 20;
    const offset = (pageNum - 1) * limitNum;

    const searchQuery = {
      [Op.or]: [
        { nickname: { [Op.like]: `%${q}%` } },
        { bio: { [Op.like]: `%${q}%` } }
      ],
      status: 'active'
    };

    const users = await User.findAll({
      where: searchQuery,
      attributes: ['nickname', 'avatarUrl', 'bio', 'statistics', 'createdAt'],
      limit: limitNum,
      offset,
      order: [['createdAt', 'DESC']]
    });

    const total = await User.count({ where: searchQuery });

    res.json({
      success: true,
      data: {
        users,
        searchQuery: q,
        pagination: {
          page: pageNum,
          limit: limitNum,
          total,
          pages: Math.ceil(total / limitNum)
        }
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   PUT /api/users/update-location
// @desc    Update user's location
// @access  Private
router.put('/update-location', auth, [
  body('latitude').isFloat({ min: -90, max: 90 }).withMessage('Invalid latitude'),
  body('longitude').isFloat({ min: -180, max: 180 }).withMessage('Invalid longitude'),
  body('city').optional().isString().withMessage('City must be a string'),
  body('district').optional().isString().withMessage('District must be a string'),
  body('province').optional().isString().withMessage('Province must be a string'),
  body('address').optional().isString().withMessage('Address must be a string')
], async (req, res, next) => {
  try {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({
        success: false,
        message: 'Validation failed',
        errors: errors.array()
      });
    }

    const { latitude, longitude, city, district, province, address } = req.body;

    const user = await User.findByPk(req.user.userId);
    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    user.location = {
      coordinates: {
        latitude,
        longitude
      },
      city: city || user.location?.city,
      district: district || user.location?.district,
      province: province || user.location?.province,
      address: address || user.location?.address
    };

    await user.save();

    res.json({
      success: true,
      message: 'Location updated successfully',
      data: {
        location: user.location
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/nearby
// @desc    Find nearby users
// @access  Private
router.get('/nearby', auth, [
  query('radius').optional().isInt({ min: 1, max: 50000 }).withMessage('Radius must be between 1 and 50000 meters'),
  query('limit').optional().isInt({ min: 1, max: 100 }).withMessage('Limit must be between 1 and 100')
], async (req, res, next) => {
  try {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({
        success: false,
        message: 'Validation failed',
        errors: errors.array()
      });
    }

    const user = await User.findByPk(req.user.userId);
    if (!user || !user.location || !user.location.coordinates) {
      return res.status(400).json({
        success: false,
        message: 'Your location is not set. Please update your location first.'
      });
    }

    const radius = parseInt(req.query.radius) || 5000; // Default 5km
    const limit = parseInt(req.query.limit) || 20;

    // 注意：MySQL中的地理位置查询需要使用特定的函数
    // 这里简化处理，先返回所有活跃用户（除了当前用户）
    const nearbyUsers = await User.findAll({
      where: {
        id: { [Op.ne]: req.user.userId }, // Exclude current user
        status: 'active'
      },
      attributes: ['nickname', 'avatarUrl', 'bio', 'location', 'statistics', 'createdAt'],
      limit,
      order: [['createdAt', 'DESC']]
    });

    res.json({
      success: true,
      data: {
        users: nearbyUsers,
        radius,
        count: nearbyUsers.length
      }
    });

  } catch (error) {
    next(error);
  }
});

// @route   GET /api/users/recommendations
// @desc    Get user recommendations based on location and interests
// @access  Private
router.get('/recommendations', auth, async (req, res, next) => {
  try {
    const user = await User.findByPk(req.user.userId, {
      include: [{
        association: 'preferences',
        attributes: ['activityTypes']
      }]
    });

    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Get recommendations based on location and preferences
    const recommendations = await User.findAll({
      where: {
        id: { [Op.ne]: req.user.userId },
        status: 'active',
        [Op.or]: [
          // Same city
          { '$location.city$': user.location?.city },
          // Similar interests
          { '$preferences.activityTypes$': { [Op.overlap]: user.preferences?.activityTypes || [] } }
        ]
      },
      attributes: ['nickname', 'avatarUrl', 'bio', 'location', 'preferences', 'statistics', 'createdAt'],
      limit: 10,
      order: [['createdAt', 'DESC']]
    });

    res.json({
      success: true,
      data: {
        recommendations,
        count: recommendations.length
      }
    });

  } catch (error) {
    next(error);
  }
});

module.exports = router;